﻿// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;

namespace NuGet.Services.Validation
{
    public class ValidationResponse : IValidationResponse
    {
        /// <summary>
        /// Represents a validation step that has not been started.
        /// </summary>
        public static IValidationResponse NotStarted { get; } = new ValidationResponse(ValidationStatus.NotStarted);

        /// <summary>
        /// Represents a validation step that has started but not succeeded or failed yet.
        /// </summary>
        public static IValidationResponse Incomplete { get; } = new ValidationResponse(ValidationStatus.Incomplete);

        /// <summary>
        /// A successful validation step with no results.
        /// </summary>
        public static IValidationResponse Succeeded { get; } = new ValidationResponse(ValidationStatus.Succeeded);

        /// <summary>
        /// A failed validation step with no results.
        /// </summary>
        public static IValidationResponse Failed { get; } = new ValidationResponse(ValidationStatus.Failed);

        /// <summary>
        /// Create a new validation step response with the given status.
        /// </summary>
        /// <param name="status">The step's status.</param>
        public ValidationResponse(ValidationStatus status)
            : this(status, results: null, outputUrl: null)
        {
        }

        /// <summary>
        /// Create a new validation step response with the given status.
        /// </summary>
        /// <param name="status">The step's status.</param>
        /// <param name="outputUrl">
        /// A URL to modified package content. Must be null if status is not 
        /// <see cref="ValidationStatus.Succeeded"/>.
        /// </param>
        public ValidationResponse(
            ValidationStatus status,
            string outputUrl)
            : this(status, results: null, outputUrl: outputUrl)
        {
        }

        /// <summary>
        /// Create a new validation step repsonse with the given status.
        /// </summary>
        /// <param name="status">The step's status.</param>
        /// <param name="results">
        /// The results generated by the validation step. These provide additional information,
        /// such as debugging information or reasons for failure.
        /// </param>
        public ValidationResponse(
            ValidationStatus status,
            IReadOnlyList<PackageValidationResult> results)
            : this(status, results, outputUrl: null)
        {
        }

        /// <summary>
        /// Create a new failed validation step response with the given errors.
        /// </summary>
        /// <param name="status">The status of the validation step.</param>
        /// <param name="results">
        /// The results generated by the validation step. These provide additional information,
        /// such as debugging information or reasons for failure.
        /// </param>
        /// <param name="outputUrl">
        /// A URL to modified package content (.nupkg). Must be null if status is not 
        /// <see cref="ValidationStatus.Succeeded"/>.
        /// </param>
        public ValidationResponse(
            ValidationStatus status,
            IReadOnlyList<PackageValidationResult> results,
            string outputUrl)
        {
            if (results?.Count > 0 && status != ValidationStatus.Succeeded && status != ValidationStatus.Failed)
            {
                throw new ArgumentException($"Cannot specify {nameof(results)} if the validation is not in a terminal status.", nameof(status));
            }

            if(!string.IsNullOrEmpty(outputUrl) && status != ValidationStatus.Succeeded)
            {
                throw new ArgumentException($"Cannot specify {nameof(outputUrl)} if the validation is not in a success state.", nameof(status));
            }

            Status = status;
            Results = results ?? Array.Empty<PackageValidationResult>();
            OutputUrl = outputUrl;
        }

        /// <summary>
        /// The status of the validation step.
        /// </summary>
        public ValidationStatus Status { get; }

        /// <summary>
        /// The results generated by the validation step. 
        /// </summary>
        public IReadOnlyList<PackageValidationResult> Results { get; }

        /// <summary>
        /// The URL to the modified NuGet/Marketplace package content. This URL should be accessible without special authentication
        /// headers. However, authentication information could be included in the URL (e.g. Azure Blob Storage SAS URL).
        /// This URL need not have a single value for a specific <see cref="ValidationId"/>.
        /// </summary>
        public string OutputUrl { get; }

        /// <summary>
        /// Create a new failed <see cref="ValidationResult"/>.
        /// </summary>
        /// <param name="results">The results for the failed validation step response.</param>
        /// <returns>The failed validation step response.</returns>
        public static ValidationResponse FailedWithResults(params PackageValidationResult[] results)
        {
            return new ValidationResponse(ValidationStatus.Failed, (PackageValidationResult[])results.Clone());
        }
    }
}
